package com.coachtam.ljgcapi.filter;

import com.coachtam.ljgcapi.utils.RequestUtils;
import com.coachtam.ljgcapi.utils.ResponseUtils;
import com.coachtam.ljgcapi.vo.ResultVO;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Charsets;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @Copyright (C), 2018-2020
 * @Author: JAVA在召唤
 * @Date: 2020-08-03 17:08
 * @Description:
 */
@Slf4j
@Component
public class RatelimiterGlobalFilter implements GatewayFilter, Ordered {


    BloomFilter<CharSequence> bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8), 200000, 1E-7);
    private final static int COUNT = 45;
    private final static int BLACK_COUNT = 50;

    // 通过CacheBuilder构建一个缓存实例
    private Cache<String, Integer> ipCouter = CacheBuilder.newBuilder()
            .maximumSize(10000) // 设置缓存的最大容量
            .expireAfterWrite(5, TimeUnit.SECONDS)
//            .expireAfterAccess(10, TimeUnit.SECONDS)// 设置缓存在写入一分钟后失效
            .concurrencyLevel(10) // 设置并发级别为10
            .recordStats() // 开启缓存统计
            .build();

    private List<String> suffixList = Arrays.asList(".htm", ".html", ".jsp", ".jspx","/");


    /**
     *
     * @param exchange
     * @param chain
     * @return
     *
     * get请求参考spring cloud gateway自带过滤器：
     * @see org.springframework.cloud.gateway.filter.factory.AddRequestParameterGatewayFilterFactory
     *
     * post请求参考spring cloud gateway自带过滤器：
     * @see org.springframework.cloud.gateway.filter.factory.rewrite.ModifyRequestBodyGatewayFilterFactory
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain){

        try {
            ServerHttpRequest request = exchange.getRequest();
            ServerHttpResponse response = exchange.getResponse();
            String path = request.getURI().getPath();

            //是否需要限流
            if(suffixList.stream().anyMatch(s->path.endsWith(s))){
                log.debug("----自定义防限流全局过滤器生效----");
                String ip = RequestUtils.getIpAddr(request);

                if (bloomFilter.mightContain(ip)) {
                    return ResponseUtils.printJson(response, ResultVO.inBackList());
                }
                Integer count = ipCouter.getIfPresent(ip);
                if(count!=null){
                    //如果缓存存在
                    log.debug("ip:{},count:{}", ip,count);
                    ipCouter.put(ip, count + 1);
                    //可以考虑将此ip加入黑名单
                    if(count > BLACK_COUNT){
                        bloomFilter.put(ip);
                        log.debug("ip:{},count:{}->已经加入黑名单", ip,count);
                        return ResponseUtils.printJson(response, ResultVO.inBackList());
                    }

                    if(count > COUNT){
                        log.debug("ip:{},count:{}->给出黑名单警告", ip,count);
                        return ResponseUtils.printJson(response, ResultVO.warnBackList());
                    }

                }
                else {
                    //此ip第一次
                    count = 1;
                }
                ipCouter.put(ip, count + 1);
            }

        }catch (Exception e)
        {
            log.error("限流过滤器异常",e);
        }


        return chain.filter(exchange);
    }



    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }


}
